// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <algorithm>
#include <cmath>
#include <string>

#include <glog/logging.h>

#include "coin2/exchange/base/order/external.h"

#ifndef NOTREACHED
#define NOTREACHED() CHECK(false)
#endif

namespace coin2::exchange::base::order {

// All input parameters must be of same type.
// type checking is done implicitly.
// If not satisfied, there will be compile error.
template <typename T>
bool EqualToAnyOf(T a, T b) {
  return a == b;
}

template <typename T, typename... U>
bool EqualToAnyOf(T v, T c1, U... c2) {
  return v == c1 || EqualToAnyOf(v, c2...);
}

inline bool IsBuyOrderSide(OrderSide order_side) {
  return EqualToAnyOf(
      order_side, OrderSide::BUY_ORDER, OrderSide::BUY_OPEN_ORDER,
      OrderSide::BUY_CLOSE_ORDER);
}

inline bool IsSellOrderSide(OrderSide order_side) {
  return EqualToAnyOf(
      order_side, OrderSide::SELL_ORDER, OrderSide::SELL_OPEN_ORDER,
      OrderSide::SELL_CLOSE_ORDER);
}

inline TradeSide OrderSideToTradeSide(OrderSide order_side) {
  if (IsBuyOrderSide(order_side)) {
    return TradeSide::TRADE_BUY_SIDE;
  } else if (IsSellOrderSide(order_side)) {
    return TradeSide::TRADE_SELL_SIDE;
  }
  NOTREACHED() << "Unknown order side!";
  return TradeSide::TRADE_NO_SIDE;
}

inline int GetSign(OrderSide order_side, bool die_on_error=true) {
  if (IsBuyOrderSide(order_side)) {
    return +1;
  } else if (IsSellOrderSide(order_side)) {
    return -1;
  }
  if (die_on_error) {
    NOTREACHED() << "Unknown order side!";
  }
  return 0;
}

inline bool IsClose(double a, double b) {
  constexpr double eps = 1e-8;
  return std::fabs(a - b) < eps;
}

}  // namespace coin2::exchange::base::order
